package com.beyondsoft.dtc.mobile.automation.uiautomator.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.beyondsoft.dtc.mobile.automation.base.GlobalConstants.ElementType;
import com.beyondsoft.dtc.mobile.automation.uiautomator.model.UiDumpModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beyondsoft.dtc.mobile.automation.uiautomator.model.Coordinate;
import com.beyondsoft.dtc.mobile.automation.util.ShellUtil;
import com.beyondsoft.dtc.mobile.automation.util.StringUtil;

/**
 * 元素定位用服务.
 *
 * @author scottche
 * @version 1.0 2016.4.19 初版创立.
 */
public class UiAutomatorHandlerService {
    /**
     * 提取的UI画面的xml文件名称.
     */
    private final static String UI_DUMP_FILE_NAME = "uidump.xml";
    /**
     * 存储在手机的位置.
     */
    private final static String UI_XML_FILE_PATH = "/data/local/tmp/"
            + UI_DUMP_FILE_NAME;
    private final Logger logger = LoggerFactory
            .getLogger(UiAutomatorHandlerService.class);
    /**
     * ADB 命令路径
     */
    private String adbPath;

    /**
     * 连接目标机器标识.
     */
    private String connectAddress;

    /**
     * 匹配坐标值用正则
     */
    private Pattern pattern = Pattern.compile("([0-9]+)");

    /*
     * 获取系统临时文件存储目录，用以存储从移动设备pull下来的xml文件.
     */
    private String tempDir = System.getProperty("java.io.tmpdir");

    /**
     * /tmp/dumpfile
     */
    private String temp = new File(tempDir + File.separator + "dumpfile")
            .getAbsolutePath();

    public void setDumps(List<UiDumpModel> dumps) {
        this.dumps = dumps;
    }

    /**
     * 存储解析xml文件后得到的所有node节点信息
     */
    private List<UiDumpModel> dumps = null;

    /**
     * 构造函数。创建存储手机发送的UI xml的文件夹.
     *
     * @param adbPath        adb命令路径
     * @param connectAddress 目标移动设备
     */
    public UiAutomatorHandlerService(String adbPath, String connectAddress) {
        this.adbPath = adbPath;
        this.connectAddress = connectAddress;
        this.temp += File.separator + connectAddress;

        File dumpFolder = new File(temp);
        if (!dumpFolder.exists()) {
            dumpFolder.mkdirs();
        }
    }

    /**
     * 提取元素属性前需要刷新时调用.
     */
    public synchronized void refresh() {
        // 目标机器截取当前画面UI XML信息
        String[] command = {adbPath, "-s", connectAddress, "shell",
                "uiautomator", "dump", UI_XML_FILE_PATH};
        ShellUtil.CommandResult commandResult = ShellUtil.execCommandNoLog(command);

        if (commandResult.isCommandSucceeded() && commandResult.getResultMsg().contains("could not get idle state")) {
//            logger.error("uiautomator" + "dump --compressed " + UI_XML_FILE_PATH);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            command = new String[]{adbPath, "-s", connectAddress, "shell",
                    "uiautomator", "dump", "--compressed", UI_XML_FILE_PATH};
            commandResult = ShellUtil.execCommand(command);
        }

        if (commandResult.isCommandSucceeded()) {
            //将目标机器截取的UI信息拉到本地，以便进行解析.
            command = new String[]{adbPath, "-s", connectAddress, "pull",
                    UI_XML_FILE_PATH, temp};
            commandResult = ShellUtil.execCommandNoLog(command);

            if (commandResult.isCommandSucceeded()) {
                command = new String[]{adbPath, "-s", connectAddress,
                        "shell", "rm", UI_XML_FILE_PATH};
                ShellUtil.execCommandNoLog(command);
            }
        }

        File file = new File(temp + File.separator + UI_DUMP_FILE_NAME)
                .getAbsoluteFile();
        try {
            InputStream xml = new FileInputStream(file);
            dumps = new UiDumpXmlFileParser().getDumps(xml);
        } catch (Exception e) {
//            logger.error(e.getMessage());
            dumps = new ArrayList<UiDumpModel>();
        }
    }

    /**
     * 通过text定位单个元素
     *
     * @return 返回元素位置坐标
     */
    public UiDumpModel findElementByKeyword(String keyword, String packageName,
                                            int sdkVersion) {
        UiDumpModel uiDumpModel = this.findElement(ElementType.TEXT.getValue(),
                keyword, packageName);
        return uiDumpModel == null ? this.findElement(
                ElementType.RESOURCE_ID.getValue(), keyword, packageName)
                : uiDumpModel;
    }

    /**
     * 通过password定位单个元素
     *
     * @return 返回元素位置坐标
     */
    public UiDumpModel findElementByPassword() {
        for (UiDumpModel dumpNode : dumps) {
            try {
                if (StringUtil.equalsIgnoreCase("true", dumpNode.getPassword())
                        && StringUtil.equalsIgnoreCase("true",
                        dumpNode.getClickable())) {
                    setCoordinate(dumpNode);
                    return dumpNode;
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
        return null;
    }

    /**
     * 通过class定位单个元素
     *
     * @param className className for searched target
     * @return 返回元素位置坐标
     */
    public UiDumpModel findElementByClass(String className) {
        for (UiDumpModel dumpNode : dumps) {
            try {
                if (dumpNode.getClassName() != null
                        && dumpNode.getClassName().contains(className)) {
                    setCoordinate(dumpNode);
                    return dumpNode;
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
        return null;
    }

    public UiDumpModel findLastButton() {
        UiDumpModel lastNode = null;
        for (UiDumpModel dumpNode : dumps) {
            try {
                if (StringUtil
                        .equalsIgnoreCase("true", dumpNode.getClickable())
                        && dumpNode.getClassName() != null
                        /*&& dumpNode.getClassName().contains(
								GlobalConstants.CLASS_TYPE_BUTTON)*/) {
                    setCoordinate(dumpNode);
                    lastNode = dumpNode;
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
        return lastNode;
    }

    /**
     * 获得前一个控件
     *
     * @param currentNode
     * @return UiDumpModel 如果没有返回null
     */
    public UiDumpModel getPreNode(UiDumpModel currentNode) {
        int index = currentNode.getIndex();
        if (index <= 0) {
            return null;
        }

        UiDumpModel preNode = dumps.get(currentNode.getIndex() - 1);
        if (preNode != null) {
            setCoordinate(preNode);
        }
        return preNode;
    }

    /**
     * 获得后一个控件
     *
     * @param currentNode
     * @return UiDumpModel 如果没有返回null
     */
    public UiDumpModel getNextNode(UiDumpModel currentNode) {
        int index = currentNode.getIndex();
        if (index >= dumps.size() - 1) {
            return null;
        }

        UiDumpModel nextNode = dumps.get(currentNode.getIndex() + 1);
        if (nextNode != null) {
            setCoordinate(nextNode);
        }
        return nextNode;
    }

    /**
     * 提取指定元素的中心点坐标.
     *
     * @param attributeId Enum of element related text
     * @param keyword     keyword for searched target text
     * @return 指定元素的坐标
     */
    private UiDumpModel findElement(int attributeId, String keyword,
                                    String packageName) {
        if (keyword == null) {
//            logger.info("keyword is null");
            return null;
        }
        // 获取元素区域中心位置坐标.例如：[496,192][640,260]
        for (UiDumpModel dumpNode : dumps) {
            Boolean flag = false;
            try {
                String text = "";
                switch (attributeId) {
                    default:
                    case 0:
                        text = dumpNode.getText();
                        break;
                    case 1:
                        text = dumpNode.getResourceId();
                        break;
                    case 2:
                        text = dumpNode.getClassName();
                        break;
                    case 3:
                        text = dumpNode.getChecked();
                        break;
                    case 4:
                        text = dumpNode.getCheckable();
                        break;
                    case 5:
                        text = dumpNode.getContentDesc();
                        break;
                    case 6:
                        text = dumpNode.getClickable();
                        break;
                    case 8:
                        text = dumpNode.getPassword();
                        break;
                }

                if (text.trim().equals("") || null == text) {
                    continue;
                }
                flag = text.toLowerCase().equals(keyword.toLowerCase())
                        && "true".equalsIgnoreCase(dumpNode.getClickable());
                if (flag && !StringUtil.isEmpty(packageName)) {
                    flag = dumpNode.getPackageName().toLowerCase()
                            .startsWith(packageName.toLowerCase());
                }
                if (flag) {
                    logger.debug("UiAutomatorHanderlerService   text : " + text
                            + "     keyword : " + keyword);
                    logger.debug(">> getAttribute >>, text [{}], element src [{}]," +
                                    " flag [{}], clickable [{}], pkgName [{}], element " +
                                    "pkgName [{}]",
                            keyword, text, flag, dumpNode.getClickable(),
                            packageName, dumpNode.getPackageName());
                    setCoordinate(dumpNode);
                    return dumpNode;
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            }

        }
        return null;
    }

    /**
     * 设置中心的值
     *
     * @param model
     */
    private void setCoordinate(UiDumpModel model) {
        CharSequence input = model.getBounds();

        // 中心点坐标：bounds="[496,192][640,260].解析提取到数组里.
        Matcher mat = pattern.matcher(input);
        ArrayList<Integer> coords = new ArrayList<Integer>();
        while (mat.find()) {
            coords.add(new Integer(mat.group()));
        }

        // 提取元素的左上和右下坐标.
        int startX = coords.get(0);
        int startY = coords.get(1);
        int endX = coords.get(2);
        int endY = coords.get(3);

        // 指定元素的中心点坐标
        int centerCoordsX = (endX - startX) / 2 + startX;
        int centerCoordsY = (endY - startY) / 2 + startY;

        Coordinate coordinate = new Coordinate();

        coordinate.setX(centerCoordsX);
        coordinate.setY(centerCoordsY);

        model.setCoordinate(coordinate);
    }

    public List<UiDumpModel> getDumps() {
        if (dumps != null && dumps.size() > 0) {
            for (UiDumpModel dump : dumps) {
                setCoordinate(dump);
            }
        }
        return dumps;
    }
}
